package org.jetlinks.pro.things.impl.rpc;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.hswebframework.web.bean.FastBeanCopier;
import org.hswebframework.web.id.IDGenerator;
import org.jetlinks.core.message.MessageType;
import org.jetlinks.core.message.ThingMessage;
import org.jetlinks.core.things.ThingRpcSupport;
import org.jetlinks.core.things.ThingType;
import org.jetlinks.core.things.ThingsRegistry;
import org.jetlinks.pro.things.ThingMessageConverter;
import org.jetlinks.pro.things.ThingsRpcSupportProvider;
import org.jetlinks.pro.things.impl.converter.TemplateThingMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Mono;

import java.util.Map;

@Component
@AllArgsConstructor
public class SimpleThingsRpcSupportProvider implements ThingsRpcSupportProvider {

    private final ThingsRegistry registry;

    @Override
    public String getId() {
        return "thing";
    }

    @Override
    public String getName() {
        return "物RPC";
    }

    @Override
    public Mono<ThingRpcSupport> createSupport(Map<String, Object> configuration) {
        ThingRpcProperties properties = FastBeanCopier.copy(configuration, new ThingRpcProperties());
        properties.validate();
        properties.prepare();
        TemplateThingMessageConverter converter = new TemplateThingMessageConverter(properties::toMessage,
                                                                                    ThingMessageConverter.expression());

        return Mono.just(new SimpleThingsRpcSupport(registry,
                                                    ThingType.of(properties.thingType),
                                                    properties.thingId,
                                                    converter));
    }

    @Getter
    @Setter
    public static class ThingRpcProperties {
        private String thingType;
        private String thingId;
        private Map<String, Object> message;

        public ThingMessage toMessage() {
            ThingMessage msg = MessageType
                .convertMessage(message)
                .filter(ThingMessage.class::isInstance)
                .map(ThingMessage.class::cast)
                .orElseThrow(() -> new IllegalArgumentException("illegal message format"));
            if (StringUtils.hasText(thingType) && StringUtils.hasText(thingId)) {
                msg.thingId(thingType, thingId);
            }
            msg.messageId(IDGenerator.SNOW_FLAKE_STRING.generate());
            return msg;
        }

        private void prepare(){
            if (StringUtils.hasText(thingType)) {
                message.put("thingType", thingType);
            }
            if (StringUtils.hasText(thingId)) {
                message.put("thingId", thingId);
            }
        }

        public void validate() {
            Assert.notEmpty(message, "message can not be empty");
            toMessage();
        }
    }
}
